// <com.woyouqiu.Copyright>
// --------------------------------------------------------------
// <copyright>上海有求网络科技有限公司 2015</copyright>
// <Solution>Vecen.BangChuang</Solution>
// <Project>Vecen.BangChuang.Core</Project>
// <FileName>AttachmentManager.cs</FileName>
// <CreateTime>2017-05-05 0:07</CreateTime>
// <Author>何苗</Author>
// <Email>hemiao@woyouqiu.com</Email>
// <log date="2017-05-05 0:07" version="00001">创建</log>
// --------------------------------------------------------------
// </com.woyouqiu.Copyright>

using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Abp;
using Abp.Dependency;
using Abp.Domain.Repositories;
using Abp.UI;
using Vecen.BangChuang.BangChuang.Common;

namespace Vecen.BangChuang.BangChuang.DomainServices.Common {
    public class AttachmentManager: BangChuangDomainServiceBase, ITransientDependency {
        private readonly IRepository<Attachment> _attachmentRepository;
        private readonly IFileStorage _fileStorage;

        public AttachmentManager(IRepository<Attachment> attachmentRepository, IFileStorage fileStorage) {
            _attachmentRepository = attachmentRepository;
            _fileStorage = fileStorage;
        }

        /// <summary>
        /// 获得指定业务对象第一个附件ID
        /// </summary>
        /// <param name="type"></param>
        /// <param name="objectId"></param>
        /// <returns></returns>
        public async Task<int?> GetIdAsync(string type, long? objectId) {
            var attr = await Task.Run(() => _attachmentRepository.GetAll()
                .OrderByDescending(c => c.CreationTime)
                .FirstOrDefault(c => c.AssociateType == type && c.ObjectId == objectId));
            return attr?.Id;
        }

        /// <summary>
        /// 获得指定业务对象所有的附件ID
        /// </summary>
        /// <param name="type"></param>
        /// <param name="objectId"></param>
        /// <returns></returns>
        public Task<List<int>> GetIdsAsync(string type, long? objectId) {
            return Task.Run(() => _attachmentRepository.GetAll()
                .Where(c => c.AssociateType == type)
                .Where(c => c.ObjectId == objectId)
                .Select(c => c.Id)
                .ToList());
        }

        /// <summary>
        /// 更新附件关联的业务对象
        /// </summary>
        /// <param name="attachmentType"></param>
        /// <param name="attachmentIds"></param>
        /// <param name="objectId"></param>
        /// <returns></returns>
        public async Task UpdateObjectIdAsync(string attachmentType, List<int> attachmentIds, long objectId) {
            var entities = await Task.Run(() => _attachmentRepository.GetAll()
                .Where(c => attachmentIds.Contains(c.Id))
                .ToList());
            foreach(var entity in entities) {
                if(entity.AssociateType != attachmentType) {
                    throw new AbpException("要更新的附件类型不正确!");
                }
                entity.ObjectId = objectId;
                await _attachmentRepository.UpdateAsync(entity);
            }
        }

        /// <summary>
        /// 删除附件
        /// </summary>
        /// <param name="attachmentType"></param>
        /// <param name="attachmentIds"></param>
        /// <returns></returns>
        public async Task DelAttachmentAsync(string attachmentType, List<int> attachmentIds) {
            var entities = _attachmentRepository.GetAll().Where(c => attachmentIds.Contains(c.Id)).ToList();
            foreach(var attachment in entities) {

                if(attachment.AssociateType != attachmentType) {
                    throw new AbpException("要删除的附件类型不正确!");
                }
                try {
                    await _fileStorage.DeleteFileAsync(attachment.FileName);
                } catch(IOException exception) {
                    Logger.ErrorFormat(exception, "删除文件出错!id:{0} fileName:{1}", attachment.Id,
                        attachment.FileName.ToString());
                }
                await _attachmentRepository.DeleteAsync(attachment);
            }
        }

        /// <summary>
        /// 保存附件
        /// </summary>
        /// <param name="type">业务类型</param>
        /// <param name="fileContent"></param>
        /// <param name="objectId">业务对象ID</param>
        /// <returns></returns>
        public async Task<int> SaveAttachmentAsync(string type, FileContent fileContent, long? objectId = null) {
            var attachment = new Attachment();
            attachment.AssociateType = type;
            attachment.ContentType = fileContent.ContentType;
            attachment.FileLength = fileContent.ContentLength;
            attachment.FriendlyFileName = fileContent.FileName;
            attachment.RemoteUrl = fileContent.RemoteUrl;
            attachment.Height = fileContent.Height;
            attachment.Width = fileContent.Width;
            attachment.ObjectId = objectId;
            if(fileContent.FileBytes != null && fileContent.FileBytes.Any()) {
                attachment.FileName = await _fileStorage.SaveFileAsync(fileContent.FileBytes);
            }
            return await _attachmentRepository.InsertAndGetIdAsync(attachment);
        }

        public async Task<FileContent> GetContentByIdAsync(int id) {
            var attachment = await _attachmentRepository.FirstOrDefaultAsync(id);
            if(attachment == null) {
                throw new UserFriendlyException("请求失败", "附件记录已不存在!");
            }
            return await AttrInfoMapToContentDto(attachment);
        }

        private async Task<FileContent> AttrInfoMapToContentDto(Attachment attachment) {
            var fileContent = new FileContent();
            fileContent.ContentLength = attachment.FileLength;
            fileContent.ContentType = attachment.ContentType;
            fileContent.FileName = attachment.FriendlyFileName;
            fileContent.RemoteUrl = attachment.RemoteUrl;
            if(!string.IsNullOrWhiteSpace(attachment.FileName.ToString())) {
                try {
                    fileContent.FileBytes = await _fileStorage.GetFileAsync(attachment.FileName);
                } catch(FileNotFoundException exception) {
                    Logger.Error(
                        string.Format("文件已被删除!附件ID:{0}\t 附件名称:{1}\t 文件名称:{2}", attachment.Id,
                            attachment.FriendlyFileName, attachment.FileName), exception);
                    throw new UserFriendlyException("下载失败", "服务器上不存在该文件!", exception);
                }
            }
            return fileContent;
        }


        /// <summary>
        /// 根据业务对象Id删除附件
        /// </summary>
        /// <param name="attachmentType"></param>
        /// <param name="objectId"></param>
        /// <returns></returns>
        public async Task DelAttachmentWithObjectIdAsync(string attachmentType, int objectId) {
            var query = _attachmentRepository.GetAll()
                .Where(c => c.AssociateType == attachmentType)
                .Where(c => c.ObjectId == objectId)
                .Select(c => c.Id);

            var ids = await Task.Run(() => query.ToList());
            await DelAttachmentAsync(attachmentType, ids);
        }
    }
}